--  ternary.vhd - balanced ternary simulation for VHDL
--
--  Copyright (C) 2018, TERNARY RESEARCH CORPORATION <vhdl@ternary.info>
--
--  This program is free software: you can redistribute it and/or modify
--  it under the terms of the GNU General Public License as published by
--  the Free Software Foundation, either version 3 of the License, or
--  (at your option) any later version.
--
--  This program is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--  GNU General Public License for more details.
--
--  You should have received a copy of the GNU General Public License
--  along with this program.  If not, see <http://www.gnu.org/licenses/>.

PACKAGE ternary IS

--      v1.0 (06-JUL-2018) - initial release

        SUBTYPE FakeTrit is BIT_VECTOR (1 downto 0);
--        SUBTYPE FakeTriad is BIT_VECTOR (5 downto 0);
--        SUBTYPE FakeTriadWithParity is BIT_VECTOR (7 downto 0);

        CONSTANT O : FakeTrit := "00";
        CONSTANT P : FakeTrit := "01";
        CONSTANT N : FakeTrit := "10";
        CONSTANT X : FakeTrit := "11";

---        FUNCTION make_triad(Th,Tm,Tl: FakeTrit) RETURN FakeTriad;
---        FUNCTION make_triad_with_parity(Th,Tm,Tl: FakeTrit) RETURN FakeTriadWithParity;

        FUNCTION buf(T: FakeTrit) RETURN FakeTrit;
        FUNCTION inv(T: FakeTrit) RETURN FakeTrit;
        FUNCTION mux(T_S: FakeTrit; T_N: FakeTrit; T_O: FakeTrit; T_P: FakeTrit) RETURN FakeTrit;
        FUNCTION e12(T_S: FakeTrit; T_N: FakeTrit; T_P: FakeTrit) RETURN FakeTrit;
        FUNCTION e21(T_S: FakeTrit; T_N: FakeTrit; T_P: FakeTrit) RETURN FakeTrit;

        PROCEDURE dmux(signal T_S: IN FakeTrit;
                       signal T_C: IN FakeTrit;
                       signal T_N: OUT FakeTrit;
                       signal T_O: OUT FakeTrit;
                       signal T_P: OUT FakeTrit);

        COMPONENT ternary_mem
        PORT (
               T_S : IN FakeTrit;
               T_N : IN FakeTrit;
               T_P : IN FakeTrit;
               T_Q : OUT FakeTrit
        );
        END COMPONENT;

        COMPONENT ternary_mux
        PORT (
               T_S : IN FakeTrit;
               T_N : IN FakeTrit;
               T_O : IN FakeTrit;
               T_P : IN FakeTrit;
               T_C : OUT FakeTrit
        );
        END COMPONENT;

        COMPONENT ternary_dmux
        PORT (
               T_S : IN FakeTrit;
               T_C : IN FakeTrit;
               T_N : OUT FakeTrit;
               T_O : OUT FakeTrit;
               T_P : OUT FakeTrit
        );
        END COMPONENT;

        COMPONENT ternary_clock
        PORT (
               B_C : IN BIT;
               T_C : OUT FakeTrit
        );
        END COMPONENT;

END PACKAGE ternary;

PACKAGE BODY ternary IS

        FUNCTION buf(T: FakeTrit) RETURN FakeTrit IS
        begin
                case T is
                when N =>
                        return N;
                when O =>
                        return O;
                when P =>
                        return P;
                when others =>
                        return X;
                end case;
        end;

        FUNCTION inv(T: FakeTrit) RETURN FakeTrit IS
        begin
                case T is
                when N =>
                        return P;
                when O =>
                        return O;
                when P =>
                        return N;
                when others =>
                        return X;
                end case;
        end;

        FUNCTION mux(T_S: FakeTrit; T_N: FakeTrit; T_O: FakeTrit; T_P: FakeTrit) RETURN FakeTrit IS
        begin
                case T_S is
                when N =>
                        return T_N;
                when O =>
                        return T_O;
                when P =>
                        return T_P;
                when others =>
                        return X;
                end case;
        end;

        FUNCTION e12(T_S: FakeTrit; T_N: FakeTrit; T_P: FakeTrit) RETURN FakeTrit IS
        begin
                return mux(T_S,T_N,T_P,T_P);
        end;

        FUNCTION e21(T_S: FakeTrit; T_N: FakeTrit; T_P: FakeTrit) RETURN FakeTrit IS
        begin
                return mux(T_S,T_N,T_N,T_P);
        end;

        PROCEDURE dmux(signal T_S: IN FakeTrit;
                       signal T_C: IN FakeTrit;
                       signal T_N: OUT FakeTrit;
                       signal T_O: OUT FakeTrit;
                       signal T_P: OUT FakeTrit) IS
        begin
                case T_S is
                when N =>
                        T_N <= T_C;
                        T_O <= O;
                        T_P <= O;
                when O =>
                        T_N <= O;
                        T_O <= T_C;
                        T_P <= O;
                when P =>
                        T_N <= O;
                        T_O <= O;
                        T_P <= T_C;
                when others =>
                        T_N <= X;
                        T_O <= X;
                        T_P <= X;
                end case;
        end;

END ternary;

-- Entity ternary_mem

USE ternary.ALL;

ENTITY ternary_mem IS
        PORT (
              T_S : IN FakeTrit;
              T_N : IN FakeTrit;
              T_P : IN FakeTrit;
              T_Q : OUT FakeTrit
        );
END ternary_mem;

ARCHITECTURE Behavioral OF ternary_mem IS
BEGIN
    PROCESS (T_S)
    BEGIN
        IF (T_S(0) = '1') THEN
            T_Q <= T_P;
        ELSIF (T_S(1) = '1') THEN
            T_Q <= T_N;
        END IF;
    END PROCESS;
END Behavioral;

-- Entity ternary_mux

USE ternary.ALL;

ENTITY ternary_mux IS
        PORT (
              T_S : IN FakeTrit;
              T_N : IN FakeTrit;
              T_O : IN FakeTrit;
              T_P : IN FakeTrit;
              T_C : OUT FakeTrit
        );
END ternary_mux;

ARCHITECTURE Behavioral OF ternary_mux IS
BEGIN
    T_C <= mux(T_S,T_N,T_O,T_P);
END Behavioral;

-- Entity ternary_dmux

USE ternary.ALL;

ENTITY ternary_dmux IS
        PORT (
              T_S : IN FakeTrit;
              T_C : IN FakeTrit;
              T_N : OUT FakeTrit;
              T_O : OUT FakeTrit;
              T_P : OUT FakeTrit
        );
END ternary_dmux;

ARCHITECTURE Behavioral OF ternary_dmux IS
BEGIN
    dmux(T_S,T_C,T_N,T_O,T_P);
END Behavioral;

-- Entity ternary_clock

USE ternary.ALL;

ENTITY ternary_clock IS
        PORT (
              B_C : IN BIT;
              T_C : OUT FakeTrit
        );
END ternary_clock;

ARCHITECTURE Behavioral OF ternary_clock IS
signal flag : bit;
BEGIN
    PROCESS (B_C)
    BEGIN
        IF (B_C'event AND B_C = '1') THEN
            IF (flag = '0') THEN
                flag <= '1';
            ELSE
                flag <= '0';
            END IF;
        END IF;
        IF (B_C = '1' AND flag = '0') THEN
            T_C(0) <= '1';
        ELSE
            T_C(0) <= '0';
        END IF;
        IF (B_C = '1' AND flag = '1') THEN
            T_C(1) <= '1';
        ELSE
            T_C(1) <= '0';
        END IF;
    END PROCESS;
END Behavioral;

